/*
 * JVM_OpcodeInvoke.c
 *
 *  Created on: 04.01.2011
 *      Author: Tavin
 */


#include "JVM_Opcode.h"
#include "JVM_OpcodeInvoke.h"
#include "JVM_StatusCodes.h"
#include "JVM_StackFrame.h"
#include "JVM_Thread.h"
#include "JVM_Native.h"




uint16_t JVM_cmd_invokevirtual()
{

	JVM_cmd_invokestatic();



	return(STCD_OK);
}



uint16_t JVM_cmd_invokespecial()
{

	JVM_cmd_invokestatic();



	return(STCD_OK);
}

/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_invokestatic							Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.5			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_cmd_invokestatic()
{


	JVM_StackFrame_t * myStackFrame;
	JVM_CP_Method_t * myMethodInfo;

	JVM_Method_t 	* myMethod;

	uint16_t index;

	index=JVM_Opcode_getCodeShort();

	myStackFrame=JVM_Opcode_getActiveStackFrame();


	myMethodInfo=JVM_CPTable_getMethodInfo(myStackFrame->currentCpTable,index);
	//TODO TypeCheck !!!!! -> error !!!!
	myMethod=myMethodInfo->adress;

	if (JVM_Method_isNative(myMethod)==TRUE)
		{
		return(JVM_Native_executeStatic(myMethodInfo));
		}
	else


	return(JVM_invokeMethod(myMethodInfo,myMethod));


}



/****************************************************************************************/
/*																						*/
/*	Function : JVM_invokeMethod								Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.5			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_invokeMethod(JVM_CP_Method_t 	* myMethodInfo,JVM_Method_t 	* myMethod)
{
	JVM_StackFrame_t * myStackFrame;
	JVM_StackFrame_t * newStackFrame;

	JVM_Thread_t * myThread;

	JVM_Class_t *myClass;
	//JVM_CP_Class_t *myClassInfo;


	uint16_t dataIndex;
	uint16_t varIndex;

	uint16_t index;

	int32_t objectHandle;


	union data_value myValue;

	int parameterCount;


	dataIndex=1;
	varIndex=0;
	myStackFrame=JVM_Opcode_getActiveStackFrame();
	uint8_t paramAdress;


//	myClassInfo=JVM_CPTable_getClassInfo(myStackFrame->currentCpTable,myMethodInfo->classIndex);
//	myClass=myClassInfo->classAdress;

	myClass=(JVM_Class_t*)myMethodInfo->realClass;

	//newStackFrame=JVM_StackFrame_new(myClass->constantPoolTable,myMethod);
	newStackFrame=JVM_StackFrame_new(myClass->constantPoolTable,myMethod);


	index=myMethod->codeLenght;


	parameterCount=myMethod->code[index++];
	paramAdress=0;
	uint8_t counter;

	for (counter=0;counter<parameterCount-1;counter++)
		{
		switch (myMethod->code[index])
			{

			case 'B':
			case 'C':
			case 'F':
			case 'I':
			case 'S':
			case 'Z':
			case 'L':
			case '[':
					paramAdress++;
				break;

			case 'J':
			case 'D':
					paramAdress+=2;
				break;


				default:
				//TODO unknown parameter -Error !!!!
				break;
			}
		}

	if (JVM_Method_isStatic(myMethod)==FALSE)
			{
			paramAdress++;
			}

	for (counter=0;counter<parameterCount-1;counter++)
		{
		switch (myMethod->code[index])
			{

			case 'B':
			case 'C':
			case 'F':
			case 'I':
			case 'S':
			case 'Z':

					paramAdress--;
					myValue.intValue=JVM_StackFrame_popIntValue(myStackFrame);
					JVM_StackFrame_setIntVar(newStackFrame,paramAdress,myValue.intValue);

					break;
			case 'L':
			case '[':
					paramAdress--;

					myValue.reference=JVM_StackFrame_popReference(myStackFrame);
					JVM_StackFrame_setReferenceVar(newStackFrame,paramAdress,myValue.reference);

					break;

			case 'J':
			case 'D':
					paramAdress-=2;
					myValue.longValue=JVM_StackFrame_popLongValue(myStackFrame);
					JVM_StackFrame_setLongVar(newStackFrame,paramAdress,myValue.longValue);

				break;


				default:
				//TODO unknown parameter -Error !!!!
				break;
			}
		}

	JVM_Class_t *objectClass;


	int b;
	if (JVM_Method_isStatic(myMethod)==FALSE)
			{
			objectHandle=JVM_StackFrame_popReference(myStackFrame);
			JVM_StackFrame_setReferenceVar(newStackFrame,0,objectHandle);


			JVM_Handle_getClass(objectHandle,(JVM_Class_t *)& objectClass);
			//TODO  check Class !! if class <=> object class , if Object Class has same Function execute derived Function
			if (myClass!=objectClass)
				{
				b=5;
				}
			}


	// TODO is this really static ??

	myThread=JVM_Thread_getActiveThread();





// getClass

	newStackFrame->previus=myThread->currentStackframe;
	myThread->currentStackframe=newStackFrame;


	activeStackFrame=newStackFrame;


	return(STCD_OK);
}




/*
 *
 */


/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_ireturn								Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.6			Status : Working   			*/
/*	Version : 2.0					Date :2011.1.15			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_cmd_ireturn()
{
	return(JVM_return(RETURN_TYPE_INT));
}



/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_lreturn								Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.6			Status : Working   			*/
/*	Version : 2.0					Date :2011.1.15			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_cmd_lreturn()
{
	return(JVM_return(RETURN_TYPE_LONG));
}
/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_freturn								Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.6			Status : Working   			*/
/*	Version : 2.0					Date :2011.1.15			Status : Working   			*/
/*																						*/
/****************************************************************************************/


uint16_t JVM_cmd_freturn()
{
	return(JVM_return(RETURN_TYPE_FLOAT));
}
/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_dreturn								Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.6			Status : Working   			*/
/*	Version : 2.0					Date :2011.1.15			Status : Working   			*/
/*																						*/
/****************************************************************************************/


uint16_t JVM_cmd_dreturn()
{
	return(JVM_return(RETURN_TYPE_DOUBLE));

}
/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_areturn								Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.6			Status : Working   			*/
/*	Version : 2.0					Date :2011.1.15			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_cmd_areturn()
{
	return(JVM_return(RETURN_TYPE_REFERENCE));
}


/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_ireturn								Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.6			Status : Working   			*/
/*	Version : 2.0					Date :2011.1.15			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_cmd_return()
{
	return(JVM_return(RETURN_TYPE_NONE));
}




/****************************************************************************************/
/*																						*/
/*	Function : JVM_return									Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.15			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_return(uint8_t type)
{

	JVM_Thread_t * myThread;
	JVM_StackFrame_t * myStackFrame;

	union data_value value;
//	double value;

	myThread=JVM_Thread_getActiveThread();


	myStackFrame=myThread->currentStackframe;

	switch (type)
		{
		case RETURN_TYPE_REFERENCE:
			value.reference=JVM_StackFrame_popReference(myStackFrame);
			JVM_StackFrame_pushReference(myStackFrame->previus,value.reference);

			break;

		case RETURN_TYPE_INT:
			value.intValue=JVM_StackFrame_popIntValue(myStackFrame);
			JVM_StackFrame_pushIntValue(myStackFrame->previus,value.intValue);

			break;

		case RETURN_TYPE_FLOAT:
			value.floatValue=JVM_StackFrame_popFloatValue(myStackFrame);
			JVM_StackFrame_pushFloatValue(myStackFrame->previus,value.floatValue);
			break;

		case RETURN_TYPE_LONG:
			value.longValue=JVM_StackFrame_popLongValue(myStackFrame);
			JVM_StackFrame_pushLongValue(myStackFrame->previus,value.longValue);
			break;

		case RETURN_TYPE_DOUBLE:
			value.doubleValue=JVM_StackFrame_popDoubleValue(myStackFrame);
			JVM_StackFrame_pushDoubleValue(myStackFrame->previus,value.doubleValue);
			break;

		default :

			break;

		}



	if (myStackFrame->previus==0)
		{
		//TODO   Kill Thread !!!
		JVM_StackFrame_destroy(myThread->currentStackframe);
		return(STCD_THREAD_EXIT);
		}
	else
		{
		myThread->currentStackframe=myStackFrame->previus;


		activeStackFrame=myThread->currentStackframe;

		JVM_StackFrame_destroy(myStackFrame);
		}

	return(STCD_OK);
}
